home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / c / bc_pas_1.zip / MIDIA.ASM < prev    next >
Assembly Source File  |  1992-12-08  |  41KB  |  1,770 lines

  1. ;#>
  2.  
  3. ;$Author:   DCODY  $
  4. ;$Date:   08 Dec 1992 16:51:22  $
  5. ;$Header:   X:/sccs/midi/midia.asv   1.7   08 Dec 1992 16:51:22   DCODY  $
  6. ;$Log:   X:/sccs/midi/midia.asv  $
  7. ;  
  8. ;     Rev 1.7   08 Dec 1992 16:51:22   DCODY
  9. ;  moved externADDR macro for Borland Link. Also, added valid
  10. ;  return codes for the init routine, which wasn't returning the
  11. ;  correct value.
  12. ;  
  13. ;     Rev 1.6   23 Sep 1992 10:34:44   DCODY
  14. ;  changed MVGetH... to mvGetH...
  15. ;  
  16. ;     Rev 1.5   04 Sep 1992 16:55:12   DCODY
  17. ;  NEAR external choked large model programs
  18. ;  
  19. ;     Rev 1.4   20 Jul 1992 11:42:44   DCODY
  20. ;  call to MVGetHWVersion requests active I/O detection. Found some
  21. ;  I/O that was not relocatable, and now performs XOR relocation.
  22. ;  
  23. ;     Rev 1.3   17 Jul 1992 13:57:30   DCODY
  24. ;  make I/O addresses relocatable.
  25. ;  
  26. ;     Rev 1.2   27 Jun 1992 15:44:56   DCODY
  27. ;  removed debug output code.
  28. ;  
  29. ;     Rev 1.1   25 Jun 1992 21:48:46   DCODY
  30. ;  PAS2 update
  31. ;  
  32. ;     Rev 1.0   15 Jun 1992 10:42:58   BCRANE
  33. ;  Initial revision.
  34. ;$Logfile:   X:/sccs/midi/midia.asv  $
  35. ;$Modtimes$
  36. ;$Revision:   1.7  $
  37. ;$Workfile:   midia.asm  $ 
  38.  
  39. ;#<
  40.  
  41.         Title   MIDIA.ASM  --  Media Vision 3802 Midi Hardware Dependent Module
  42.     Subttl    Copyright (c) 1991,1992. Media Vision Inc. All Rights Reserved.
  43.     page    64,131
  44.  
  45. ;   /*\
  46. ;---|*|-----------------------====< MIDIA.ASM >====------------------------
  47. ;---|*|
  48. ;---|*| Low Level MIDI I/O routines for the Pro Audio Spectrum cards.
  49. ;---|*|
  50. ;   \*/
  51.  
  52.     .xlist
  53.     include model.inc
  54.     include masm.inc
  55.     include mvmidi.inc
  56.     include common.inc
  57.     include target.inc
  58.         .list
  59.  
  60. ;
  61. ;   /*\
  62. ;---|*|----====< int mvMIDIEnable >====----
  63. ;---|*|
  64. ;---|*| mvMIDIEnable - Initialize the MIDI interface
  65. ;---|*|
  66. ;---|*|   Entry Conditions:
  67. ;---|*|      wParm1 is a bit field for process control
  68. ;---|*|      D0 = 1 to enable input interrupts
  69. ;---|*|      D1 = 1 to enable output interrupts
  70. ;---|*|
  71. ;---|*|   Exit Conditions:
  72. ;---|*|      AX = -1 if cannot init the MIDI hardware.
  73. ;---|*|
  74. ;---|*|----====< void mvMIDIDisable >====----
  75. ;---|*|
  76. ;---|*| mxdDisable - MIDI shutdown
  77. ;---|*|
  78. ;---|*| Entry Conditions
  79. ;---|*|     None
  80. ;---|*|
  81. ;---|*| Exit Conditions
  82. ;---|*|     There is no return value.
  83. ;---|*|
  84. ;---|*|----====< int mvMIDIGetBuff >====----
  85. ;---|*|
  86. ;---|*| mvMIDIGetBuff - get data byte from MIDI channel
  87. ;---|*|
  88. ;---|*| Entry Conditions
  89. ;---|*|     wParm1 holds the count to move
  90. ;---|*|     dParm2 points to the target buffer
  91. ;---|*|
  92. ;---|*| Exit Conditions
  93. ;---|*|     AX = 0, no data, # of bytes moved
  94. ;---|*|
  95. ;---|*|----====< int mvMIDIGetByte >====----
  96. ;---|*|
  97. ;---|*| mvMIDIGetByte - get/check one byte from MIDI channel buffer
  98. ;---|*|
  99. ;---|*| Entry Conditions
  100. ;---|*|     None
  101. ;---|*|
  102. ;---|*| Exit Conditions
  103. ;---|*|     AX = byte, or -1 if no data
  104. ;---|*|
  105. ;---|*|----====< void mvMIDISendBuff >====----
  106. ;---|*|
  107. ;---|*| mvMIDISendBuff - send a buffer of data
  108. ;---|*|
  109. ;---|*| Entry Conditions
  110. ;---|*|     wParm1 = integer of count to load
  111. ;---|*|     dParm1 = far pointer to the buffer
  112. ;---|*|
  113. ;---|*| Exit Conditions
  114. ;---|*|     There is no return value.
  115. ;---|*|
  116. ;---|*|----====< void mvMIDISendByte >====----
  117. ;---|*|
  118. ;---|*| mvMIDISendByte - send data byte out MIDI channel
  119. ;---|*|
  120. ;---|*| Entry Conditions
  121. ;---|*|     wParm1  datum
  122. ;---|*|
  123. ;---|*| Exit Conditions
  124. ;---|*|     There is no return value.
  125. ;---|*|
  126. ;   \*/
  127. ;
  128.  
  129.     externADDR  mvGetHWVersion          ; determine the installed hardware type
  130.  
  131.     .data
  132. ;
  133. ;   /*\
  134. ;---|*|------------====< Global Data Definitions >====------------
  135. ;   \*/
  136. ;
  137.     extrn    _MVTranslateCode:word
  138.     extrn    _MVHWVersionBits:word
  139. ;
  140. ; The overflow count will always be here, but we won't make it public
  141. ; except for debugging purposes
  142. ;
  143.  
  144. ifdef DEBUG
  145.         public  _overflow
  146. endif
  147. _overflow       dw      0               ; overflow count
  148.  
  149. ;
  150. ; MidiInFilter allows certain types of MIDI messages to be tossed out...
  151. ;
  152. ;   NOTE: this currently works for active sense ONLY.
  153. ;
  154.     public    _MidiInFilter
  155. _MidiInFilter    dw    MF_ACTSENSE    ; default ignores active sense
  156.  
  157. ;
  158. ;   /*\
  159. ;---|*|------------====< Private Data Definitions >====------------
  160. ;   \*/
  161. ;
  162.  
  163. ;
  164. ; This midi code uses interrupt driven I/O, so a circular buffer is used
  165. ; to support the data flow.
  166. ;
  167.  
  168. MAXQUEUE    equ    128
  169.  
  170. ;
  171. ; MIDI input circular buffer
  172. ;
  173. iCircularQueue    db    MAXQUEUE    dup (0)
  174.  
  175. MIDIiQueueCnt    dw    0
  176.  
  177. lpiMIQueue    dw    iCircularQueue
  178. lpiMOQueue    dw    iCircularQueue
  179.  
  180. ;
  181. ; MIDI output circular buffer
  182. ;
  183. oCircularQueue    db    MAXQUEUE    dup (0)
  184.  
  185. MIDIoQueueCnt    dw    0
  186.  
  187. lpoMIQueue    dw    oCircularQueue
  188. lpoMOQueue    dw    oCircularQueue
  189.  
  190. ;
  191. ; Interrupt channel number and mask
  192. ;
  193.  
  194. _IRQNumb        db      -1
  195. _IRQMask    db    0
  196.  
  197. ;
  198. ; Interrupt Service Routine re-entrancy sema-phore
  199. ;
  200. ISRbusy         db      -1              ; ISR semaphore
  201.  
  202. ;
  203. ; Internal process control to handle polled or interrupt driven data I/O
  204. ;
  205. ProcessControl  db      0               ; Interrupt or polled I/O
  206. INTINPUT    equ    00000001b
  207. INTOUTPUT    equ    00000010b    ; (currently not implemented)
  208.  
  209.  
  210. ;
  211. ;   /*\
  212. ;---|*|------------====< Yamaha 3802 midi interface variables >====------------
  213. ;   \*/
  214. ;
  215.  
  216. MDctrl        db    0    ; MDSYSCTLR shadow for write only hardware
  217. ISRenab     db    0    ; R06 TX and RX int enable bits
  218.  
  219. ; r02/r03/r06 bit definitions
  220. TxIRQ    equ    01000000b    ; Tx FIFO interrupt
  221. RxIRQ    equ    00100000b    ; Rx FIFO interrupt
  222.  
  223. ; r34 bit definitions
  224. RxRDY    equ    10000000b    ; Rx FIFO non-empty
  225.  
  226. ; r54 bit definitions
  227. TxEMP    equ    10000000b    ; Tx FIFO empty
  228. TxRDY    equ    01000000b    ; Tx FIFO non-full
  229.  
  230. TIMER1    equ    2173
  231.  
  232. ;
  233. ;------------------------================================----------------------
  234. ;------------------------====< MIDI Common Routines >====----------------------
  235. ;------------------------================================----------------------
  236. ;
  237.         .code
  238.     assume    ds:@data,es:nothing
  239.  
  240. ;
  241. ; We will save the old IRQ vector here to guarrantee access at all times.
  242. ;
  243.  
  244. OldISR          dd      0               ; holds the original IRQ vector
  245.  
  246. ;
  247. ;    Toggle the MIDI interrupt to stimulate latent IRQs
  248. ;
  249. ToggleMV101mask macro
  250.  
  251.         mov     dx,INTRCTLR
  252.     xor    dx,[_MVTranslateCode]
  253.  
  254.     in    al,dx            
  255.     xor    al,bICmidi    ; disable MIDI interrupts
  256.     out    dx,al
  257.     pause
  258.     xor    al,bICmidi    ; enable MIDI interrupts
  259.     out    dx,al
  260.  
  261.     endm
  262.  
  263. ;
  264. ;   /*\
  265. ;---|*|----====< int mvMIDIEnable >====----
  266. ;---|*|
  267. ;---|*| Initialize the MIDI interface
  268. ;---|*|
  269. ;---|*| Entry Conditions:
  270. ;---|*|       wParm1 is a bit field for process control:
  271. ;---|*|      D0 = 1 to enable input interrupts.
  272. ;---|*|      D1 = 1 to enable output interrupts.
  273. ;---|*|
  274. ;---|*| Exit Conditions:
  275. ;---|*|     AX = -1 if cannot init the MIDI hardware.
  276. ;---|*|
  277. ;   \*/
  278. ;
  279.         public  mvMIDIEnable
  280. mvMIDIEnable   proc
  281.     push    bp            ; frame the stack for our 1 parameter
  282.     mov    bp,sp
  283. ;
  284. ; reset the MIDI buffering system
  285. ;
  286.     mov    [lpiMIQueue],OFFSET iCircularQueue
  287.     mov    [lpiMOQueue],OFFSET iCircularQueue
  288.     mov    [lpoMIQueue],OFFSET oCircularQueue
  289.     mov    [lpoMOQueue],OFFSET oCircularQueue
  290.     mov    [MIDIoQueueCnt],0
  291.     mov    [MIDIiQueueCnt],0
  292.     mov    [_overflow],0
  293.     mov    [_MidiInFilter],MF_ACTSENSE
  294. ;
  295. ; If the hardware bits have not been determined, do it...
  296. ;
  297.     cmp    _MVHWVersionBits,-1    ; version bits = -1 if the function
  298.     jnz    @F            ; hasn't been called yet.
  299.     mov    ax,USE_ACTIVE_ADDR    ; do the call
  300.     push    ax            ; to setup the hardware bits, etc.
  301.     call    mvGetHWVersion
  302.     pop    ax
  303.     ;
  304.     @@:
  305. ;
  306. ; determine the IRQ for the Pro Audio card
  307. ;
  308.     call    whereirq        ; looks for MVSOUND.SYS
  309. ;
  310. ; convert each bit to a full mask. Send this mask to each routine.
  311. ;
  312.     mov    ax,wParm1        ; load the bit flags
  313.     mov    [ProcessControl],al    ; save as our process control
  314.     ror    ax,1            ; ah holds input bit, al holds output
  315.     neg    ah
  316.     sbb    ah,ah            ; ah = FF to enable ints, else 0
  317.     neg    al
  318.     sbb    al,al            ; al = FF to enable ints, else 0
  319. ;
  320. ; perform the proper init
  321. ;
  322.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  323.     jz    @F             ; no, go do yamaha
  324. ;
  325. ; initialize the MV101 MIDI device
  326. ;
  327.         call    enable_mv101
  328.     mov    ax,-1            ; default to bad
  329.     jc    mvmienbad        ; cannot set it up...
  330.     inc    ax            ; return oky doky...
  331.     pop    bp
  332.         ret
  333. ;
  334. @@:
  335. ;
  336. ; initialize the Yamaha 3802
  337. ;
  338.         call    enable_yamaha
  339.     mov    ax,-1            ; default to bad
  340.     jc    mvmienbad        ; cannot set it up...
  341.     inc    ax            ; return oky doky...
  342. ;
  343. mvmienbad:
  344.     pop    bp
  345.         ret
  346.  
  347. mvMIDIEnable   endp
  348.  
  349. ;
  350. ;   /*\
  351. ;---|*|----====< void mvMIDIDisable >====----
  352. ;---|*|
  353. ;---|*| MIDI device shutdown.
  354. ;---|*|
  355. ;---|*| Entry Conditions:
  356. ;---|*|     None.
  357. ;---|*|
  358. ;---|*| Exit Conditions:
  359. ;---|*|     There is no return value.
  360. ;---|*|
  361. ;   \*/
  362. ;
  363.         public  mvMIDIDisable
  364. mvMIDIDisable  proc
  365. ;
  366. ; remove ourselves from the chain
  367. ;
  368.         call    unhook_interrupt
  369. ;
  370. ; perform the proper init
  371. ;
  372.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  373.     jz    @F             ; no, go do yamaha
  374.  
  375.     call    disable_MV101        ; disable the MV101 MIDI
  376.         ret
  377.     ;
  378.     @@:
  379.     call    disable_yamaha        ; disable the Yamaha MIDI
  380. ;
  381. midblexit:
  382.         ret
  383.  
  384. mvMIDIDisable  endp
  385.  
  386. ;
  387. ;   /*\
  388. ;---|*|----====< int mvMIDIGetBuff >====----
  389. ;---|*|
  390. ;---|*| Get data byte from MIDI channel.
  391. ;---|*|
  392. ;---|*| Entry Conditions
  393. ;---|*|     wParm1 holds the count to move.
  394. ;---|*|     dParm2 points to the target buffer.
  395. ;---|*|
  396. ;---|*| Exit Conditions
  397. ;---|*|     AX = 0, no data, # of bytes moved.
  398. ;---|*|
  399. ;   \*/
  400. ;
  401.         public  mvMIDIGetBuff
  402. mvMIDIGetBuff  proc
  403.     push    bp
  404.     mov    bp,sp
  405. ;
  406. ; save the C criticals
  407. ;
  408.         push    es
  409.     push    si
  410.     push    di
  411. ;
  412. ; load the parameters
  413. ;
  414.         mov     cx,wParm1               ; get the number of bytes to move
  415.     les    di,wParm2        ; get the target pointer
  416.     mov    si,[lpiMOqueue]     ; get the source pointer
  417.     sub    dx,dx            ; dx holds the # of bytes moved
  418.     cld
  419. ;
  420. ; using interrupt driven input?
  421. ;
  422.         test    [ProcessControl],INTINPUT
  423.     jz    mvigb_20        ; polled, check each h/w
  424. ;
  425. mvigb_05:
  426. ;
  427. ; read as many bytes out of the queues until one is empty, or full.
  428. ;
  429.     cmp    [MIDIiQueueCnt],0    ; all done?
  430.     jz    mvigb_10        ; yes, return # of bytes moved
  431.     movsb
  432.     dec    [MIDIiQueueCnt]     ; one less byte here...
  433.     inc    dx
  434.     cmp    si,offset iCircularQueue+MAXQUEUE
  435.     jl    @F
  436.     mov    si,offset iCircularQueue
  437.     ;
  438.     @@:
  439.     loop    mvigb_05        ; get it all...
  440. ;
  441. mvigb_10:
  442.     mov    [lpiMOQueue],si     ; save the pointer
  443.     mov    ax,dx
  444. ;
  445. mvigb_ret:
  446.     pop    di
  447.     pop    si
  448.     pop    es
  449.     pop    bp
  450.         ret
  451. ;
  452. mvigb_20:
  453. ;
  454. ; This is a little slow, but avoids messy code duplication
  455. ;
  456.     push    si            ; save si
  457.     mov    si,cx            ; si will be our loop counter
  458.     mov    bp,cx            ; bp will hold the total count
  459. ;
  460. mvigb_25:
  461.     call    FFAR ptr mvMIDIGetByte    ; get the next byte
  462.     cmp    ax,-1            ; any data?
  463.     jz    mvigb_30        ; nope, we're done...
  464.     stosb                ; save in the callers buffer
  465.     dec    si            ; all done?
  466.     jnz    mvigb_25        ; nope, continue looping
  467. ;
  468. mvigb_30:
  469.         sub     bp,si                   ; bp holds the total read count
  470.     mov    ax,bp
  471.     pop    si
  472.     jmp    short mvigb_ret
  473.  
  474. mvMIDIGetBuff  endp
  475.  
  476. ;
  477. ;   /*\
  478. ;---|*|----====< int mvMIDIGetByte >====----
  479. ;---|*|
  480. ;---|*| Get one byte from MIDI channel buffer.
  481. ;---|*|
  482. ;---|*| Entry Conditions
  483. ;---|*|     None.
  484. ;---|*|
  485. ;---|*| Exit Conditions
  486. ;---|*|     AX = -1 if no data.
  487. ;---|*|     AH =  0 if data in AL.
  488. ;---|*|
  489. ;   \*/
  490. ;
  491.         public  mvMIDIGetByte
  492. mvMIDIGetByte  proc
  493. ;
  494. ; If the code is running as interrupt input, then we can check the queue
  495. ;
  496.         test    [ProcessControl],INTINPUT
  497.     jz    mvgbt_20        ; polled, check each h/w
  498.  
  499.     cmp    [MIDIiQueueCnt],0    ; any data?
  500.     jz    mvgbt_none        ; no, just return now
  501.  
  502.     mov    bx,[lpiMOqueue]     ; get the source pointer
  503.     sub    ah,ah            ; clear out the top
  504.     mov    al,[bx]         ; load the bottom
  505.  
  506.     dec    [MIDIiQueueCnt]     ; one less byte here...
  507.     inc    bx
  508.     cmp    bx,offset iCircularQueue+MAXQUEUE
  509.     jl    mvgbt_05
  510.     mov    bx,offset iCircularQueue
  511. ;
  512. mvgbt_05:
  513.     mov    [lpiMOqueue],bx     ; save the new pointer
  514.         ret
  515. ;
  516. mvgbt_none:
  517.     mov    ax,-1            ; bad, so exit with error flag
  518.     ret
  519. ;
  520. mvgbt_20:
  521. ;
  522. ; This is the polled mode of MIDI input - go check the correct chip FIFO
  523. ;
  524.         test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  525.     jz    mvgbt_yamaha         ; no, go do yamaha
  526. ;
  527. ; read the MV101 MIDI fifo
  528. ;
  529.     mov    dx,MIDISTATUS        ; check data available
  530.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  531.  
  532.     in    al,dx            ; isolate the data available bit
  533.     and    ax,bMSRififo
  534.     jz    mvgbt_none        ; no data available, go report it...
  535.  
  536.     mov    dx,MIDIDATA
  537.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  538.  
  539.     in    al,dx            ; return the byte in al, ah = 0
  540.  
  541.     ret
  542. ;
  543. mvgbt_yamaha:
  544. ;
  545. ; read the Yamaha 3802 MIDI fifo.
  546. ;
  547.         mov     al, 3                   ; 3x
  548.     mov    dx, MDSYSCTLR        ; set the 3802 global reg set index
  549.     mov    [MDctrl],al        ; shadow...
  550.     out    dx, al
  551.  
  552.         mov     dx, MDGROUP4            ; 34 = FIFO-Rx status
  553.     in    al, dx
  554.     and    ax, RxRDY        ; RxRDY bit?
  555.         jz      mvgbt_none              ; no data available, go report it...
  556.  
  557.     mov    dx, MDGROUP6        ; 36 = FIFO-Rx data
  558.  
  559.     in    al, dx            ; return the byte in al, ah = 0
  560.  
  561.     ret
  562.  
  563. mvMIDIGetByte  endp
  564.  
  565. ;
  566. ;   /*\
  567. ;---|*|----====< void mvMIDISendByte >====----
  568. ;---|*|
  569. ;---|*| mvMIDISendByte - send a MIDI data byte out the MIDI channel.
  570. ;---|*|
  571. ;---|*| Entry Conditions
  572. ;---|*|     wParm1 - MIDI byte to be sent.
  573. ;---|*|
  574. ;---|*| Exit Conditions
  575. ;---|*|     There is no return value.
  576. ;   \*/
  577. ;
  578.     public    mvMIDISendByte
  579. mvMIDISendByte    proc
  580. ;
  581. ; send the byte out directly if polled output, else queue it up to keep order
  582. ;
  583.         push    bp
  584.     mov    bp,sp
  585.  
  586.     mov    al,wParm1        ; grab the byte
  587.  
  588.     test    [ProcessControl],INTOUTPUT ; interrupt output?
  589.     jnz    mvsnd_ints           ; yes, we will queue it...
  590.  
  591.         call    dosendbyte              ; send it out straight
  592.  
  593.         pop     bp
  594.     ret
  595. ;
  596. mvsnd_ints:
  597. ;
  598. ; Interrupt driven output requires the byte be queue to keep the byte order.
  599. ;
  600.         mov     bx,[lpoMIQueue]         ; get the input-to-buffer pointer
  601. ;
  602. @@:
  603.     cmp    [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
  604.     jnz    @F            ; no, go load another byte
  605.     call    primexmit        ; make sure the xmitter is working
  606.     jmp    short @B        ; go wait for data to move
  607. ;
  608. @@:
  609.     mov    [bx],al
  610.     inc    bx
  611.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  612.     jnz    @F
  613.     mov    bx,offset oCircularQueue      ; yes, go back to the beginning
  614. ;
  615. @@:
  616.         mov     [lpoMIQueue],bx         ; save the new input-to-buffer pointer
  617.     inc    [MIDIoQueueCnt]     ; add one more into the FIFO
  618.  
  619.         call    primexmit               ; make sure the xmitter is working
  620.     pop    bp
  621.     ret
  622.  
  623. mvMIDISendByte endp
  624.  
  625. ;
  626. ;   /*\
  627. ;---|*|----====< void mvMIDISendBuff >====----
  628. ;---|*|
  629. ;---|*| mvMIDISendBuff - send a buffer of data.
  630. ;---|*|
  631. ;---|*| Entry Conditions
  632. ;---|*|     wParm1 = integer of count to load.
  633. ;---|*|     dParm1 = far pointer to the buffer.
  634. ;---|*|
  635. ;---|*| Exit Conditions
  636. ;---|*|     Returns when all the bytes are loaded in the circular queue.
  637. ;   \*/
  638. ;
  639.     public    mvMIDISendBuff
  640. mvMIDISendBuff    proc
  641.         push    bp
  642.     mov    bp,sp            ; 'C' frame
  643.  
  644.     push    es            ; save the 'C' criticals
  645.     push    si
  646. ;
  647. ; we will load the entire block into the FIFO. This even means waiting for the
  648. ; transmitter to empty enough data until we're done.
  649. ;
  650.     mov    cx,wParm1        ; get the buffer counter
  651.     les    si,wParm2        ; get the far pointer
  652.     mov    bx,[lpoMIQueue]     ; get the input-to-buffer pointer
  653. ;
  654. queueloop:
  655.     cmp    [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
  656.     jnz    @F            ; no, go load another byte
  657.     call    primexmit        ; make sure the xmitter is working
  658.     jmp    short queueloop
  659. ;
  660. @@:
  661.     lods    byte ptr es:[si]    ; get the next MIDI byte
  662.     mov    [bx],al
  663.     inc    bx
  664.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  665.     jnz    @F
  666.     mov    bx,offset oCircularQueue      ; yes, go back to the beginning
  667. ;
  668. @@:
  669.     inc    [MIDIoQueueCnt]     ; add one more into the FIFO
  670.     loop    queueloop        ; load all the bytes into the queue
  671.     mov    [lpoMIQueue],bx     ; save the new input-to-buffer pointer
  672. ;
  673. ; We've loaded the FIFO. if polling, call the output routine till done.
  674. ;
  675.     test    [ProcessControl],INTOUTPUT ; interrupt driven output?
  676.     jnz    sendbuffints           ; yes, force the xmitter to work
  677. ;
  678. ; this byte goes out the MV101
  679. ;
  680.     @@:
  681.     call    primexmit        ; make sure the xmitter is working
  682.     cmp    [MIDIoQueueCnt],0    ; any more queued up data?
  683.     jnz    @B            ; yes, stay here till sent...
  684.  
  685.     jmp    short sendbuffexit    ; all done, return home
  686. ;
  687. sendbuffints:
  688. ;
  689. ; make sure the xmitter is primed to generate interrupts
  690. ;
  691.     call    primexmit
  692. ;
  693. sendbuffexit:
  694.     pop    si
  695.     pop    es
  696.     pop    bp
  697.     ret
  698.  
  699. mvMIDISendBuff endp
  700.  
  701. ;
  702. ;---------------------------==============================---------------------
  703. ;---------------------------====< Local Subroutines > ====---------------------
  704. ;---------------------------==============================---------------------
  705. ;
  706.  
  707. ;
  708. ;   /*\
  709. ;---|*|----====< disable_MV101 >====----
  710. ;---|*|
  711. ;---|*| This routine will disable any MV101 MIDI
  712. ;---|*| interrupts and reset the tranceiver.
  713. ;---|*|
  714. ;---|*| Entry Conditions:
  715. ;---|*|     None.
  716. ;---|*|
  717. ;---|*| Exit Conditions:
  718. ;---|*|     AX, DX modified
  719. ;---|*|
  720. ;   \*/
  721. ;
  722. disable_MV101    proc    near
  723.  
  724.     mov    dx,MIDICONTROL        ; get the control address
  725.     xor    dx,[_MVTranslateCode]    ; translate the address
  726.  
  727.         sub     al,al                   ; flush all enables
  728.     out    dx,al            ; kill fifo irq
  729.  
  730.         ret
  731.  
  732. disable_MV101   endp
  733.  
  734. ;
  735. ;   /*\
  736. ;---|*|----====< disable_yamaha >====----
  737. ;---|*|
  738. ;---|*| This routine will disable any Yamaha MIDI
  739. ;---|*| interrupts and reset the tranceiver.
  740. ;---|*|
  741. ;---|*| Entry Conditions:
  742. ;---|*|     None.
  743. ;---|*|
  744. ;---|*| Exit Conditions:
  745. ;---|*|     AX, DX modified
  746. ;---|*|
  747. ;   \*/
  748. ;
  749. disable_yamaha  proc    near
  750. ;
  751. ; disable interrupts in the yamaha 3802
  752. ;
  753.     sub    ax, ax
  754.     mov    [MDctrl], al
  755.     mov    dx, MDSYSCTLR
  756.     out    dx, al            ; 0x
  757.  
  758.         mov     dx, MDGROUP6            ; 06 = IRQ enable request
  759.     out    dx, al
  760.  
  761.         .errnz  MDGROUP6-MDGROUP5-1
  762.  
  763.     dec    dx            ; 05 = IRQ mode control
  764.     out    dx, al
  765.  
  766.         ret
  767.  
  768. disable_yamaha    endp
  769.  
  770. ;
  771. ;   /*\
  772. ;---|*|----====< dosendbyte >====----
  773. ;---|*|
  774. ;---|*| A generic routine to send one byte out to the hardware.
  775. ;---|*|
  776. ;---|*| Entry Conditions;
  777. ;---|*|     AL holds the byte to be sent.
  778. ;---|*|
  779. ;---|*| Exit Conditions:
  780. ;---|*|     AX,BX,CX,DX modified.
  781. ;---|*|     Byte sent, no return value.
  782. ;---|*|
  783. ;   \*/
  784. ;
  785. dosendbyte      proc    near
  786. ;
  787. ; save the byte until we need it...
  788. ;
  789.         mov     ah,al                   ; ah holds the byte to send
  790. ;
  791. ; select the proper chip.
  792. ;
  793.         test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  794.     jz    send_yamaha         ; no, go do yamaha
  795. ;
  796. ; this byte goes out the MV101
  797. ;
  798.     mov    dx, MIDIFIFOS        ; get the transmitter status
  799.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  800. ;
  801. ; we will only load up to 15 bytes in the output FIFO since a zero count
  802. ; means either 16 bytes free or 0 bytes free. By only loading 15 bytes max,
  803. ; we assume a zero means 16 bytes free.
  804. ;
  805.     in    al,dx            ; get the FIFO output free room count
  806.     and    al,bMFCofifo        ; isolate the count
  807.     jz    mvsendit        ; 16 bytes free
  808.     sub    cx,cx            ; we will do a timeout
  809.     ;
  810.     @@:
  811.     in    al, dx            ; get the FIFO counts
  812.     and    al, bMFCofifo        ; any room in the output FIFO?
  813.     cmp    al, 10h         ; one byte left in the FIFO?
  814.     loopz    @b            ; wait till there is more room
  815.     jcxz    deadtx            ; exit on a timeout
  816. ;
  817. mvsendit:
  818.     mov    dx, MIDIDATA        ; get the data output port
  819.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  820.  
  821.     mov    al, ah
  822.     out    dx, al            ; ship stuff...
  823. ;
  824. deadtx:
  825.         ret
  826. ;
  827. send_yamaha:
  828. ;
  829. ; this byte goes out the yamaha 3802
  830. ;
  831.         mov     al, 5                   ; 5x
  832.     mov    [MDctrl], al        ; shadow it...
  833.     mov    dx, MDSYSCTLR        ; get the port
  834.     out    dx, al            ; let'er rip...
  835.  
  836.     mov    dx, MDGROUP4        ; 54 = FIFO-Tx status
  837. ;
  838. @@:     in      al, dx
  839.     test    al, TxRDY        ; TxRDY bit?
  840.     jz    @b            ; ..jump if FIFO full
  841.  
  842.     mov    dl, LOW MDGROUP6    ; 56 = FIFO-Tx data
  843.     mov    al, ah
  844.     out    dx, al            ; ship datum
  845.  
  846.     ret
  847.  
  848. dosendbyte    endp
  849.  
  850. ;
  851. ;   /*\
  852. ;---|*|----====< enable_mv101 >====----
  853. ;---|*|
  854. ;---|*| Enable the MV101 tranceiver, and any appropriate interrupts
  855. ;---|*|
  856. ;---|*| Entry Conditions:
  857. ;---|*|     AH = FF to enable input interrupts
  858. ;---|*|     AL = FF to enable output interrupts
  859. ;---|*|
  860. ;---|*| Exit Conditions:
  861. ;---|*|     AX,BX,CX,DX modified.
  862. ;---|*|     Carry clear -- assumed to be good
  863. ;---|*|
  864. ;   \*/
  865. ;
  866. enable_mv101    proc    near
  867. ;
  868. ; build the correct mask bits in ah
  869. ;
  870.     and    ax,(bMCRenafifoi SHL 8) + bMCRenafifoo
  871.     or    ah,al            ; ah holds the enable bits
  872. ;
  873. ; do something to the test register
  874. ;
  875. ;;;    mov    dx,MIDITEST
  876. ;;;    xor    dx,[_MVTranslateCode]    ; translated I/O addr
  877. ;;;    mov    al,0FFh
  878. ;;;    out    dx,al
  879. ;
  880. ; setup the MIDI prescale
  881. ;
  882.         mov     dx,MIDIPRESCALE
  883.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  884.     mov    al,10h            ;
  885.     out    dx,al
  886. ;
  887. ; reset the fifos
  888. ;
  889.     mov    dx,MIDICONTROL
  890.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  891.     mov    al,bMCRrstfifoi+bMCRrstfifoo
  892.     out    dx,al            ; send the reset bits
  893.     mov    al,ah
  894.     out    dx,al            ; clear reset bits and set enables
  895. ;
  896. ; reset any present status bits
  897. ;
  898.         mov     dx,MIDISTATUS
  899.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  900.     mov    al,-1            ; reset all midi status bits
  901.     out    dx,al
  902. ;
  903. ; only enable the stuff if we're using interrupts
  904. ;
  905.     test    [ProcessControl],INTINPUT+INTOUTPUT
  906.     jz    enamv_done        ; no interrupts, just exit now...
  907. ;
  908. ; install the interrupt handling now
  909. ;
  910.     cli
  911.  
  912.     lea    ax,MV101_ISR
  913.     call    hook_interrupt        ; insert our routine
  914.  
  915.     sti
  916. ;
  917. enamv_done:
  918.     clc
  919.     ret
  920.  
  921. enable_mv101    endp
  922.  
  923. ;
  924. ;   /*\
  925. ;---|*|----====< enable_yamaha >====----
  926. ;---|*|
  927. ;---|*| Enable the Yamaha 3802 tranceiver, and any appropriate interrupts.
  928. ;---|*|
  929. ;---|*| Enable the 3802 Yamaha MIDI device
  930. ;---|*|     AH = FF to enable input interrupts.
  931. ;---|*|     AL = FF to enable output interrupts.
  932. ;---|*|
  933. ;---|*| Exit Conditions:
  934. ;---|*|     AX,BX,CX,DX modified.
  935. ;---|*|     Carry clear -- assumed to be good
  936. ;---|*|
  937. ;   \*/
  938. ;
  939. enable_yamaha    proc      near
  940. ;
  941. ; build the correct mask bits in ah
  942. ;
  943.     and    ax,(RxIRQ SHL 8)+ TxIRQ
  944.     or    al,ah            ; al holds the enable bits
  945.     push    ax            ; save the interrupt enable bits
  946. ;
  947. ; reset the 3802 midi chip
  948. ;
  949.     mov    al, 80h         ; master clear
  950.     mov    [MDctrl], al
  951.     mov    dx, MDSYSCTLR
  952.     out    dx, al
  953.  
  954.     mov    cx, 100
  955. @@:    in    al, dx            ; wait 32 TCLK
  956.     loop    @b
  957.  
  958.     xchg    ax,cx            ; load zero
  959.     out    dx,al            ; flush the reset bit
  960.  
  961.     mov    al, 6
  962.     mov    [MDctrl], al
  963.     out    dx, al            ; 6x
  964.     mov    dx, MDGROUP6        ; 66 = Click counter control
  965.     mov    al, 00000010b        ; Clock=1.0MHz, no click pulse
  966.     out    dx, al
  967.  
  968.     mov    al, 4
  969.     mov    [MDctrl], al
  970.     mov    dx, MDSYSCTLR
  971.     out    dx, al            ; 4x
  972.     mov    dx, MDGROUP4        ; 44 = Tx communication rate
  973.     mov    al, 00001000b        ; CLKM/32 = 31,250 bps
  974.     out    dx, al
  975.  
  976.     mov    al, 2
  977.     mov    [MDctrl], al
  978.     mov    dx, MDSYSCTLR
  979.     out    dx, al            ; 2x
  980.     mov    dx, MDGROUP4        ; 24 = Rx communication rate
  981.     mov    al, 00001000b        ; CLKM/32 = 31,250 bps
  982.     out    dx, al
  983.  
  984.     mov    al, 5
  985.     mov    [MDctrl], al
  986.     mov    dx, MDSYSCTLR
  987.     out    dx, al            ; 5x
  988.     mov    dx, MDGROUP5        ; 55 = FIFO-Tx control
  989.     mov    al, 10000101b        ; TxE
  990.     out    dx, al
  991.  
  992.     mov    al, 8
  993.     mov    [MDctrl], al
  994.     mov    dx, MDSYSCTLR
  995.     out    dx, al            ; 8x
  996.     mov    dx, MDGROUP4        ; 84 = General Timer LSB
  997.     mov    ax, TIMER1
  998.     out    dx, al
  999.     mov    dx, MDGROUP5        ; 85 = General Timer MSB
  1000.     xchg    ah, al
  1001.     out    dx, al
  1002. ;
  1003. ; clear the FIFO-Rx
  1004. ;
  1005.     mov    al, 3            ; 35 = RCR: FIFO-Rx control
  1006.     mov    [MDctrl], al        ; bit 7 = clear FIFO-Rx
  1007.     mov    dx, MDSYSCTLR        ; bit 6 = clear RxOV flag
  1008.     out    dx, al            ; bit 4 = enable MIDI-clock filter
  1009.     mov    dx, MDGROUP5        ; bit 3 = clear BRK flag
  1010.     mov    al, 11001101b        ; bit 2 = clear RxOL flag
  1011.     out    dx, al            ; bit 1 = enable Address-hunter
  1012. ;
  1013. ; only enable the stuff if we're using interrupts
  1014. ;
  1015.     test    [ProcessControl],INTINPUT+INTOUTPUT
  1016.     jz    enayam_already        ; no interrupts, just exit now...
  1017. ;                    ; bit 0 = enable Receiver
  1018. ; initialize the 3802 chip IRQ system
  1019. ;
  1020.         sub     al, al
  1021.     mov    [MDctrl], al
  1022.     mov    dx, MDSYSCTLR
  1023.     out    dx, al            ; 0x
  1024.     mov    dx, MDGROUP5        ; 05 = IRQ mode control
  1025.     mov    al, 0011b        ; VE+VM
  1026.     out    dx, al
  1027. ;
  1028. ; initialize the board and motherboard IRQ systems
  1029. ;
  1030.         cli
  1031.  
  1032.         .errnz  MDGROUP6-MDGROUP5-1
  1033.         inc     dx
  1034.  
  1035.     pop    ax            ; get the interrupt enable bits
  1036.         out     dx, al
  1037.     mov    [ISRenab], al
  1038.  
  1039.         mov     dx, MDGROUP4            ; flush any pending IRQs
  1040.     mov    al, 0ffh
  1041.     out    dx,al
  1042. ;
  1043. ; hook the actual vector
  1044. ;
  1045.     lea    ax,Yamaha_ISR
  1046.         call    hook_interrupt
  1047.         sti
  1048.  
  1049.         clc
  1050.     ret
  1051. ;
  1052. enayam_already:
  1053.     pop    ax
  1054.     clc
  1055.     ret
  1056.  
  1057. enable_yamaha    endp
  1058.  
  1059. ;
  1060. ;   /*\
  1061. ;---|*|----====< hook_interrupt >====----
  1062. ;---|*|
  1063. ;---|*| Hook the Pro Audio hardware interrupt,
  1064. ;---|*| and enable the system interrupt.
  1065. ;---|*|
  1066. ;---|*| Entry Conditions:
  1067. ;---|*|     None.
  1068. ;---|*|
  1069. ;---|*| Exit Conditions:
  1070. ;---|*|     AX,BX,CX,DX modified.
  1071. ;---|*|
  1072. ;   \*/
  1073. ;
  1074. hook_interrupt  proc    near
  1075.         push    ds
  1076.     push    es
  1077.  
  1078.     cmp    wptr cs:[OldISR+2],0    ; any segment?
  1079.     jnz    midihooked        ; yes, we've hooked already
  1080.  
  1081.     push    ax            ; save the IRQ offset
  1082.  
  1083.     mov    ax, 3508h        ; DOS : get vector
  1084.     cmp    [_IRQNumb],7        ; 1st IRQ channel?
  1085.     jbe    @F
  1086.     mov    al,70h-8        ; 2nd IRQs start at 70H
  1087.     ;
  1088.     @@:
  1089.     add    al, [_IRQNumb]        ; IRQ
  1090.     push    ax            ; save the IRQ #
  1091.  
  1092.     int    21h            ; fetch the vector
  1093.  
  1094.     mov    wptr cs:[OldISR+0], bx    ; save original value
  1095.     mov    wptr cs:[OldISR+2], es
  1096.  
  1097.     pop    ax
  1098.         pop     dx                      ; get the actual offset
  1099.  
  1100.         push    ds                      ; save ds over the int call
  1101.     push    cs
  1102.     pop    ds            ; ds:dx point to the vector
  1103.     mov    ah, 25h         ; DOS : set vector
  1104.     int    21h
  1105.     pop    ds
  1106. ;
  1107. ; enable the Pro Audio IRQ channel
  1108. ;
  1109.     pushf
  1110.     cli
  1111. ;
  1112. ; address the correct IRQ controller
  1113. ;
  1114.     mov    dx,IRQ1MASKREG
  1115.     cmp    [_IRQNumb],7        ; 1st IRQ controller?
  1116.     jbe    @F            ; yes, continue on...
  1117.     mov    dx,IRQ2MASKREG        ; no, use the 2nd interrupt
  1118.     ;
  1119.     @@:
  1120. ;
  1121. ; Enable the correct IRQ channel
  1122. ;
  1123.         in      al, dx                  ; enable the system IRQ
  1124.     mov    ah, [_IRQMask]
  1125.     not    ah
  1126.     and    al, ah
  1127.     out    dx, al
  1128. ;
  1129. ; Enable the Pro Audio MIDI interrupt
  1130. ;
  1131.     mov    dx, INTRCTLR        ; Enable the PAS. This could signal
  1132.     xor    dx, [_MVTranslateCode]
  1133.     in    al, dx            ; an interrupt immediately.
  1134.     or    al, bICmidi        ; MIDI interrupt enable
  1135.     out    dx, al
  1136.  
  1137.     popf
  1138.     ;
  1139.     midihooked:
  1140.  
  1141.         pop     es
  1142.     pop    ds
  1143.     ret
  1144.  
  1145. hook_interrupt  endp
  1146.  
  1147. ;
  1148. ;   /*\
  1149. ;---|*|----====< void primexmit >====----
  1150. ;---|*|
  1151. ;---|*| Prime the transmitter. If interrupt driven output, make sure the
  1152. ;---|*| outbound FIFO has at least one byte loaded. If polled, send
  1153. ;---|*| the next polled byte.
  1154. ;---|*|
  1155. ;---|*| Entry Conditions:
  1156. ;---|*|    Working registers assumed to hold data.
  1157. ;---|*|
  1158. ;---|*| Exit Conditions:
  1159. ;---|*|    No registers modified.
  1160. ;---|*|
  1161. ;   \*/
  1162. ;
  1163. primexmit    proc    near
  1164. ;
  1165. ; save everything for the caller
  1166. ;
  1167.     pushf                ; save the flags so we can CLI
  1168.     push    ax            ; don't mess with any other registers
  1169.     push    dx
  1170.         push    bx
  1171.     push    cx
  1172. ;
  1173. ; Interrupt driven output is a special case. We just have to prime the pump...
  1174. ;
  1175.     test    [ProcessControl],INTOUTPUT ; interrupt driven output?
  1176.     jnz    prixmints           ; yes, force the xmitter to work
  1177. ;
  1178. prixprimeit:
  1179. ;
  1180. ; This is polled output mode. We just send one byte out. The caller will keep
  1181. ; calling us till the queue is emptied.
  1182. ;
  1183.     cmp    [MIDIoQueueCnt],0    ; any data to send?
  1184.     jz    prixdone        ; no, it's all loaded and gone..
  1185.  
  1186.         mov     bx,[lpoMOQueue]         ; get the out-of-buffer pointer
  1187.     mov    al,[bx]
  1188.     inc    bx
  1189.  
  1190.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  1191.     jnz    @F
  1192.     mov    bx,offset oCircularQueue      ; yes, wrap it...
  1193. ;
  1194. @@:
  1195.     mov    [lpoMOQueue],bx     ; save the new input-to-buffer pointer
  1196.     dec    [MIDIoQueueCnt]     ; add one more into the FIFO
  1197.  
  1198.     call    dosendbyte        ; send it via the polled routines
  1199. ;
  1200. prixdone:
  1201. ;
  1202. ; return with nothing changed
  1203. ;
  1204.         pop     cx
  1205.     pop    bx
  1206.     pop    dx
  1207.     pop    ax
  1208.     popf
  1209.     ret
  1210. ;
  1211. prixmints:
  1212. ;
  1213. ; in case of some MIDI interrupts occuring when we don't expect it, (such
  1214. ; as MIDI in interrupts) this section will be executed without interrupts
  1215. ; to avoid double sending, or sending data from the queue out of order.
  1216. ;
  1217.     cli                ; no ints while we go to prime the pump
  1218. ;
  1219. ; Make sure the transmitter FIFO has data loaded. This guarrantees an interrupt
  1220. ; when the FIFO is empty.
  1221. ;
  1222.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  1223.     jz    prixyamaha         ; no, go do yamaha
  1224.  
  1225.     mov    dx, MIDIFIFOS        ; get the transmitter FIFO status
  1226.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  1227.  
  1228.         in      al,dx                   ; get the FIFO output free room count
  1229.     and    al,bMFCofifo        ; isolate the outbound count
  1230.     jnz    prixdone        ; there is data, no need to prime it.
  1231.     jmp    short prixprimeit    ; 16 bytes free - load one more...
  1232. ;
  1233. prixyamaha:
  1234. ;
  1235. ; Yamaha 3802 - we go to TX register set 05 to find the TX empty bit
  1236. ;
  1237.     mov    al, 5            ; reg set 5x is for the xmitter
  1238.     mov    [MDctrl], al
  1239.     mov    dx, MDSYSCTLR
  1240.     out    dx, al            ; 5x
  1241.  
  1242.         mov     dx, MDGROUP4            ; 84 = General Timer LSB
  1243.     in    al,dx
  1244.     test    al,TxEMP        ; is the transmitter empty?
  1245.     jnz    prixprimeit        ; yes, go load another byte
  1246.     jmp    short prixdone        ; no, leave it alone
  1247.  
  1248. primexmit    endp
  1249.  
  1250. ;
  1251. ;   /*\
  1252. ;---|*|----====< unhook_interrupt >====----
  1253. ;---|*|
  1254. ;---|*| If installed, disable the IRQ system, then unhook
  1255. ;---|*| the Pro Audio IRQ handler from the chain.
  1256. ;---|*|
  1257. ;---|*| Entry Conditions:
  1258. ;---|*|    None.
  1259. ;---|*|
  1260. ;---|*| Exit Conditions:
  1261. ;---|*|    AX,BX,CX,DX may be modified.
  1262. ;---|*|
  1263. ;   \*/
  1264. ;
  1265. unhook_interrupt        proc    near
  1266. ;
  1267. ; don't do this if there is no need
  1268. ;
  1269.     cmp    wptr cs:[OldISR+2],0    ; interrupt already unhooked?
  1270.     jz    unhooked        ; yes, just exit
  1271. ;
  1272. ; disable system interrupt for the Pro Audio card
  1273. ;
  1274.     pushf
  1275.         cli
  1276.  
  1277.     test    al,fICintmaskbits    ; any other interrupts enabled
  1278.     jnz    mskint_done        ; yes, leave the system mask alone
  1279.  
  1280.     mov    dx,IRQ1MASKREG
  1281.     cmp    [_IRQNumb],7        ; 1st IRQ controller?
  1282.     jbe    @F            ; yes, continue on...
  1283.     mov    dx,IRQ2MASKREG        ; no, use the 2nd interrupt
  1284.     ;
  1285.     @@:
  1286.     cmp    [_IRQNumb],2        ; hardware IRQ 2?
  1287.     jz    mskint_done        ; yes, never mask it
  1288.  
  1289.     in    al,dx
  1290.     or    al,[_IRQMask]        ; no, kill the system interrupts
  1291.     out    dx,al
  1292. ;
  1293. mskint_done:
  1294.     mov    dx, INTRCTLR        ; disable the Pro Audio MIDI IRQ
  1295.     xor    dx, [_MVTranslateCode]
  1296.     in    al, dx
  1297.     and    al, not bICmidi     ; MIDI interrupt disable
  1298.     out    dx, al
  1299.  
  1300.     popf
  1301. ;
  1302. ; calculate the correct vector and restore it.
  1303. ;
  1304.     mov    ax, 2508h        ; DOS : set vector
  1305.     cmp    [_IRQNumb],7        ; 1st IRQ channel?
  1306.     jbe    @F
  1307.     mov    al,70h-8        ; 2nd IRQs start at 70H
  1308.     ;
  1309.     @@:
  1310.     add    al, [_IRQNumb]        ; IRQ
  1311. ;
  1312. ; do it through DOS...
  1313. ;
  1314.         push    ds
  1315.     lds    dx, cs:[OldISR]
  1316.     int    21h
  1317.     pop    ds
  1318.  
  1319.     mov    wptr cs:[OldISR+2],0    ; flush the segment of the vector
  1320. ;
  1321. unhooked:
  1322.         ret
  1323.  
  1324. unhook_interrupt    endp
  1325.  
  1326. ;
  1327. ;   /*\
  1328. ;---|*|----====< whereirq >====----
  1329. ;---|*|
  1330. ;---|*| This routine queries MVSOUND.SYS for the Pro Audio IRQ. Once
  1331. ;---|*| determined, then an appropriate interrupt mask will be
  1332. ;---|*| generated, and saved for future reference.
  1333. ;---|*|
  1334. ;---|*| Entry Conditions:
  1335. ;---|*|    None.
  1336. ;---|*|
  1337. ;---|*| Exit Conditions:
  1338. ;---|*|    AX,BX,CX,DX may be modified.
  1339. ;---|*|
  1340. ;   \*/
  1341. ;
  1342. whereirq        proc    near
  1343. ;
  1344. ; Do this just once
  1345. ;
  1346.     cmp    [_IRQNumb],-1        ; have we been through here?
  1347.     jnz    IRQdone         ; yes, it's been found
  1348. ;
  1349. ; Call MVSOUND.SYS to get the DMA/IRQ
  1350. ;
  1351.     mov    ax,0bc04h        ; call MVSOUND.SYS for it...
  1352.     int    2fh
  1353. ;
  1354. ; register the IRQ if the call was good
  1355. ;
  1356.     cmp    ax,'MV'                 ; was this a good call?
  1357.     jnz    IRQdone
  1358.  
  1359.     mov    [_IRQNumb],cl        ; save the #
  1360.     mov    ax,1
  1361.     shl    ax,cl
  1362.     or    al,ah
  1363.     mov    [_IRQMask],al        ; save the mask.
  1364. ;
  1365. IRQdone:
  1366.     ret
  1367.  
  1368. whereirq        endp
  1369.  
  1370. ;
  1371. ;------------------------===================================-------------------
  1372. ;------------------------====< MIDI Interrupt Service > ====-------------------
  1373. ;------------------------===================================-------------------
  1374. ;
  1375.  
  1376. ;
  1377. ;   /*\
  1378. ;---|*|----====< MV101_ISR >====----
  1379. ;---|*|
  1380. ;---|*|  ISR service routine for the MV101 MIDI interrupts.
  1381. ;---|*|
  1382. ;   \*/
  1383. ;
  1384. MV101_ISR    proc    far
  1385.     push    ds
  1386.     push    ax
  1387.     push    bx
  1388.     push    cx
  1389.     push    dx
  1390.  
  1391.     mov    ax,@data
  1392.     mov    ds,ax
  1393. ;
  1394. ; first time in, check for a MIDI interrupt
  1395. ;
  1396.     mov    dx,INTRCTLRST
  1397.     xor    dx,[_MVTranslateCode]    ; translate the address
  1398.  
  1399.     in    al,dx            ; get the interrupt status
  1400.     test    al,bISmidi        ; is this our interrupt?
  1401.     jnz    mv_is_midi_int        ; yes, go process it...
  1402.  
  1403.     test    al,fISints        ; are any of these interrupt legit?
  1404.     jjz    midiint_done        ; no, flush this int.
  1405. ;
  1406. ; this was not our interrupt, chain on...
  1407. ;
  1408.     pop    dx
  1409.     pop    cx
  1410.     pop    bx
  1411.         pop     ax
  1412.     pop    ds
  1413.     jmp    dword ptr cs:[OldISR]    ; pass off to the other code.
  1414. ;
  1415. mv_is_midi_int:
  1416. ;
  1417. ; check the receiver for data, or errors
  1418. ;
  1419.     mov    dx,MIDISTATUS
  1420.     xor    dx,[_MVTranslateCode]        ; translate the address
  1421.     in    al,dx
  1422.     mov    ah,al                ; save a copy for xmitter
  1423.  
  1424.     and    al,bMSRframeerr+bMSRififoovr+bMSRofifoovr ; overrun or frame error?
  1425.     jz    mvmidi_int            ; nope
  1426.     out    dx,al                ; clear errors
  1427.  
  1428.     mov    dx,MIDICONTROL
  1429.     xor    dx,[_MVTranslateCode]        ; translate the address
  1430.  
  1431.     in    al,dx
  1432.     or    al,bMCRrstfifoi+bMCRrstfifoo    ; reset FIFO in ptr
  1433.         out     dx,al
  1434.     or    al,NOT(bMCRrstfifoi+bMCRrstfifoo)
  1435.     out    dx,al
  1436. ;
  1437. mvmidi_int:
  1438. ;
  1439. ; get the status once again for the second chance loop
  1440. ;
  1441.         mov     dx,MIDISTATUS
  1442.     xor    dx,[_MVTranslateCode]    ; translate the address
  1443.     in    al,dx
  1444. ;
  1445. ; Only process the interrupt process wanted by the user
  1446. ;
  1447.     test    [ProcessControl],INTINPUT ; interrupt driven input?
  1448.     jz    checktrans        ; no, go check for int driven xmit
  1449.  
  1450.     test    al,bMSRififo        ; any data in input FIFO?
  1451.     jz    checktrans        ; no, go check the transmitter
  1452.  
  1453.     .errnz    MIDIFIFOS-MIDISTATUS-1
  1454.  
  1455.     inc    dx            ; move to the status register
  1456.  
  1457.     in    al,dx
  1458.     mov    cl,al
  1459.     and    cx,bMFCififo        ; get # of bytes in FIFO
  1460.     jnz    @F
  1461.     mov    cx,16
  1462.     ;
  1463.     @@:
  1464.     mov    dx,MIDIDATA        ; move to the data register
  1465.     xor    dx,[_MVTranslateCode]    ; translate the address
  1466.     mov    bx,[lpiMIQueue]     ; get  the input queue pointer
  1467. ;
  1468. mvrxloop:
  1469. ;
  1470. ; read the data off the receiver
  1471. ;
  1472.     in    al,dx            ; fetch the received byte
  1473. ;
  1474. ; MIDI spec requires transmitter send something every 300 msec
  1475. ; Active Sense (FE) is the standard "nothing for you" byte
  1476. ;
  1477.     test    [_MidiInFilter],MF_ACTSENSE ; filter out active sense
  1478.     jz    @F            ; no, keep it...
  1479.     cmp    al, 0FEh        ; Active Sense?
  1480.     je    rxCont            ; ..ignore it
  1481.     ;
  1482.     @@:
  1483.     cmp    [MIDIiQueueCnt],MAXQUEUE; is it full?
  1484.     jle    @F            ; no, save it
  1485.     inc    [_overflow]        ; yes, list it as an error
  1486.     jmp    short mvrxloop
  1487.     ;
  1488.     @@:
  1489.     mov    [bx],al
  1490.     inc    bx
  1491.     inc    [MIDIiQueueCnt]     ; one more in...
  1492.     cmp    bx,offset iCircularQueue+MAXQUEUE
  1493.     jb    rxCont
  1494.     mov    bx,offset iCircularQueue
  1495.     ;
  1496.     rxCont:
  1497.     loop    mvrxloop        ; do all bytes listed in the queue
  1498.     mov    [lpiMIQueue],bx     ; save the input queue pointer
  1499.     jmp    second_check        ; make sure FIFO is empty
  1500. ;
  1501. checktrans:
  1502. ;
  1503. ; If we are using interrupt driven output, load the FIFO now...
  1504. ;
  1505.     test    [ProcessControl],INTOUTPUT; interrupt driven output?
  1506.     jz    second_check          ; no, just exit out
  1507.  
  1508.     ; reset the interrupt now.
  1509.  
  1510.         mov     dx,MIDISTATUS
  1511.     xor    dx,[_MVTranslateCode]    ; translate the address
  1512.     mov    al,bMSRofifo        ; any data in output FIFO?
  1513.     out    dx,al
  1514.  
  1515.         ; check for any outgoing data
  1516.  
  1517.     cmp    [MIDIoQueueCnt],0    ; any queued up data?
  1518.     jz    second_check        ; no, just exit out
  1519.  
  1520.     mov    dx,MIDIFIFOS
  1521.     xor    dx,[_MVTranslateCode]    ; translate the address
  1522.  
  1523.         in      al,dx
  1524.     and    ax,bMFCofifo        ; get # of outgoing bytes
  1525.     mov    cl,4
  1526.     shr    al,cl            ; right hand justify the number
  1527.     xchg    ax,cx
  1528.     cmp    cl,1            ; down to 1 byte free?
  1529.     je    second_check        ; yes, can't load it
  1530.     ja    @F            ; we have 15 or less entries
  1531.     mov    cx,16            ; 16 entires fit, but...
  1532.     ;
  1533.     @@:
  1534.     dec    cx            ; we only load 15...
  1535.     mov    dx,MIDIDATA        ; move to the data register
  1536.     xor    dx,[_MVTranslateCode]    ; translate the address
  1537.     mov    bx,[lpoMOQueue]     ; get  the input queue pointer
  1538.     ;
  1539.     txLoop:
  1540.     mov    al,[bx]         ; pass the next byte
  1541.     out    dx,al
  1542.  
  1543.     inc    bx            ; move the pointer
  1544.     cmp    bx,offset oCircularQueue+MAXQUEUE
  1545.     jb    @F
  1546.     mov    bx,offset oCircularQueue; it wrapped...
  1547.     ;
  1548.     @@:
  1549.     dec    [MIDIoQueueCnt]     ; any queued up data?
  1550.     loopnz    txLoop
  1551.     mov    [lpoMOQueue],bx
  1552. ;
  1553. ; all done with input and output processing. Check for more interrupts
  1554. ;
  1555. second_check:
  1556. ;
  1557. ; in case we received more MIDI data during this routine, check again...
  1558. ;
  1559.         mov     dx,INTRCTLRST
  1560.     xor    dx,[_MVTranslateCode]    ; translate the address
  1561.  
  1562.     in    al,dx            ; get the interrupt status
  1563.     test    al,bISmidi        ; is the interrupt still active?
  1564.     jjnz    mvmidi_int        ; yes, go process it...
  1565. ;
  1566. midiint_done:
  1567.     mov    al,EOI            ; acknowledge the interrupt.
  1568.     cmp    [_IRQNumb],7
  1569.     jbe    @F
  1570.     out    IRQ2ACKREG, al        ; ack the 2nd IRQ controller
  1571.     ;
  1572.     @@:
  1573.     out    IRQ1ACKREG, al        ; ack the 1st IRQ controller
  1574.  
  1575.     ToggleMV101mask         ; make sure the line stays active
  1576. ;
  1577. busy_exit:
  1578.         pop     dx
  1579.     pop    cx
  1580.     pop    bx
  1581.         pop     ax
  1582.     pop    ds
  1583.         iret
  1584.  
  1585. MV101_ISR    endp
  1586.  
  1587. ;
  1588. ;   /*\
  1589. ;---|*|----====< Yamaha_ISR >====----
  1590. ;---|*|
  1591. ;---|*| ISR service routine for the Yamaha 3802 interrupts.
  1592. ;---|*|
  1593. ;   \*/
  1594. ;
  1595. Yamaha_ISR    proc    far
  1596.     push    ds            ; minimal save
  1597.     push    dx
  1598.     push    ax
  1599.  
  1600.     mov    ax, @data        ; establish our DS
  1601.     mov    ds, ax
  1602.  
  1603.     mov    dx, INTRCTLRST
  1604.     in    al, dx            ; acknowledge interrupt
  1605.     test    al, bICmidi        ; our MIDI interrupt?
  1606.     jnz    isourint        ; yes, go do it...
  1607.  
  1608.     pushf
  1609.     call    dword ptr cs:[OldISR]    ; perform the old interrupt
  1610.     jmp    WOOPS_exit
  1611. ;
  1612. isourint:
  1613. ;
  1614. ; we can now process all MIDI interrupts here
  1615. ;
  1616.     push    es
  1617.     push    di
  1618.         cld                             ; fatal to assume
  1619. ;
  1620. ; We will only process interrupt generated input if ProcessControl says so.
  1621. ;
  1622.     test    [ProcessControl],INTINPUT ; Int input?
  1623.     jz    emptyRX           ; polled, check each h/w
  1624. ;
  1625. ; Check for Rx IRQ (means FIFO-Rx went non-empty) empty the FIFO
  1626. ;
  1627.     mov    dx, MDSYSSTAT        ; IRQ Status
  1628.     in    al, dx
  1629.     and    al, RxIRQ        ; FIFO-RX non-empty?
  1630.     jz    emptyRX         ; ..jump if not
  1631.  
  1632.     .errnz    MDIRQCLR-MDSYSSTAT-1
  1633.  
  1634.     inc    dx
  1635.         out     dx,al                   ; flush it...
  1636. ;
  1637. ; get the input queue & load'er up!
  1638. ;
  1639.         mov     ax,ds
  1640.     mov    es,ax
  1641.     mov    di,lpiMIQueue        ; get the input to the queue
  1642.    ;
  1643.    rxISR_05:
  1644.     mov    al, 3            ; 3x
  1645.     mov    dx, MDSYSCTLR
  1646.     out    dx, al
  1647.  
  1648.         mov     dx, MDGROUP4            ; 34 = FIFO-Rx status
  1649.     in    al, dx
  1650.     test    al, RxRDY        ; RxRDY bit?
  1651.     jz    rxISR_10        ; ..jump if FIFO empty
  1652.  
  1653.     mov    dx, MDGROUP6        ; 36 = FIFO-Rx data
  1654.     in    al, dx            ; fetch datum
  1655. ;
  1656. ; Eliminate some overhead! The    MIDI spec requires transmitter send something
  1657. ; every 300 msec. Active Sense (FE) is the standard "nothing for you" byte
  1658. ;
  1659.     test    [_MidiInFilter],MF_ACTSENSE ; filter out active sense
  1660.     jz    @F                ; no, keep it...
  1661.     cmp    al, ACTV_SENSE            ; Active Sense?
  1662.     je    rxISR_05            ; ..ignore it
  1663.     ;
  1664.     @@:
  1665.     cmp    [MIDIiQueueCnt],MAXQUEUE; is it full?
  1666.     jle    @F            ; no, save it
  1667.     inc    _overflow
  1668.         jmp     short rxISR_05
  1669.     ;
  1670.     @@:
  1671.         stosb
  1672.     inc    [MIDIiQueueCnt]     ; one more in...
  1673.     cmp    di,offset iCircularQueue+MAXQUEUE
  1674.     jb    rxISR_05
  1675.     mov    di,offset iCircularQueue
  1676.  
  1677.     jmp    rxISR_05
  1678.    ;
  1679.    rxISR_10:
  1680.     mov    [lpiMIQueue],di     ; get the input to the queue
  1681. ;
  1682. emptyRX:
  1683. ;
  1684. ; Check for Transmitter Empyt IRQ here
  1685. ;
  1686.     test    [ProcessControl],INTOUTPUT ; Int output?
  1687.     jz    endMIDIint           ; no, exit out...
  1688.  
  1689.         mov     dx, MDSYSSTAT           ; IRQ Status
  1690.     in    al, dx
  1691.     and    al, TxIRQ        ; FIFO-Tx became empty?
  1692.     jz    endMIDIint        ; ..jump if not
  1693.  
  1694.         .errnz  MDIRQCLR-MDSYSSTAT-1
  1695.  
  1696.     inc    dx
  1697.         out     dx,al                   ; flush it...
  1698. ;
  1699. ; output any data till done.
  1700. ;
  1701.     cmp    [MIDIoQueueCnt],0    ; any data in the queue?
  1702.     jz    endMIDIint        ; ..jump if not
  1703.  
  1704.         mov     di,lpoMOQueue           ; get the pointer to the queue
  1705.     mov    dx, MDSYSCTLR        ; index to Xmitter
  1706.     mov    al,5
  1707.     out    dx,al
  1708. ;
  1709. ytxLoop:
  1710.     mov    dx, MDGROUP4        ; 54 = FIFO-Tx status
  1711.     in    al, dx
  1712.     test    al, TxRDY        ; TxRDY bit?
  1713.     jz    ytxDone         ; ..jump if FIFO full
  1714.  
  1715.     mov    dx, MDGROUP6        ; 56 = FIFO-Tx data
  1716.     mov    al, [di]
  1717.         out     dx, al                  ; ship datum
  1718.  
  1719.     inc    di            ; move the pointer
  1720.     cmp    di,offset oCircularQueue+MAXQUEUE
  1721.     jb    @F
  1722.     mov    di,offset oCircularQueue; it wrapped...
  1723.     ;
  1724.     @@:
  1725.     dec    [MIDIoQueueCnt]     ; any queued up data?
  1726.     jnz    ytxLoop         ; do as much as possible
  1727. ;
  1728. ytxDone:
  1729.     mov    [lpoMOQueue],di     ; save the ending pointer
  1730. ;
  1731. endMIDIint:
  1732. ;
  1733. ; all int handling is done now, so restore the state & exit home...
  1734. ;
  1735.         pop     di
  1736.     pop    es
  1737.  
  1738.         mov     al, [MDctrl]
  1739.         mov     dx, MDSYSCTLR
  1740.         out     dx, al                  ; restore incoming state
  1741. ;
  1742. WOOPS_reenter:
  1743. ;
  1744. ; flush the data ready IRQ
  1745. ;
  1746.     mov    al,EOI            ; acknowledge at the system level
  1747.     cmp    _IRQNumb,7
  1748.     jbe    @F
  1749.     out    IRQ2ACKREG, al        ; ack the 2nd IRQ controller
  1750.     ;
  1751.     @@:
  1752.     out    IRQ1ACKREG, al        ; ack the 1st IRQ controller
  1753.  
  1754.     ToggleMV101mask         ; make sure the MV101 can generate ints
  1755. ;
  1756. WOOPS_exit:
  1757.         pop     ax
  1758.         pop     dx
  1759.         pop     ds
  1760.     iret
  1761.  
  1762. Yamaha_ISR    endp
  1763.  
  1764. ;   /*\
  1765. ;---|*| end of MIDIA.ASM
  1766. ;   \*/
  1767.  
  1768.     end
  1769.  
  1770.